<script setup>
import { ref, watch } from 'vue';
import { ElMessage } from 'element-plus';
import axios from 'axios';
import useQuestionnaire from '@/hooks/useQuestionnaire';


const props = defineProps({
  modelValue: {
    type: [Array, String, null],
    required: true
  },
  option: {
    type: Object,
    required: false,
    default: () => ({})
  },
  templateFiles: {
    type: Array,
    required: false,
    default: () => []
  },
  disabled: {
    type: Boolean,
    required: false,
    default: false
  }
});

const emit = defineEmits(['update:modelValue']);

const { uploadConfig, getFullUrl } = useQuestionnaire();

const isArray = Array.isArray(props.modelValue);

const fileList = ref([]);

watch(() => props.modelValue, (value) => {

  if (isArray) {
    fileList.value = value || [];
  } else {

    if (!value) {
      return;
    }

    // value: 'http://xxx.com/xxx.jpg'
    const name = value.split('/').pop();

    fileList.value = [{
      name,
      url: value,
      size: 0,
      uid: Date.now()
    }];
  }
}, {
  immediate: true
});

watch(() => fileList.value, (files) => {
  if (isArray) {
    emit('update:modelValue', files);
  } else {
    emit('update:modelValue', files[0]?.url || '');
  }
}, {
  deep: true
});

const option = Object.assign({
  uploadText: '上传附件',
  uploadLimit: 10,
  uploadType: '',
  maxSize: 100
}, props.option);

async function handleChange(file, fileList) {
  file = file.raw;

  if (!await handleBeforeUpload(file)) {
    // 删除文件
    fileList.splice(fileList.findIndex(item => item.uid === file.uid), 1);

    return;
  }

  axios({
    method: uploadConfig.value.method,
    url: uploadConfig.value.uploadUrl,
    headers: {
      'Content-Type': 'multipart/form-data',
      ...uploadConfig.value.headers
    },
    data: {
      file,
      ...uploadConfig.value.data
    },
    onUploadProgress: (progressEvent) => {
      const progress = progressEvent.progress;

      const _file = fileList.find(item => item.uid === file.uid);

      if (_file) {
        _file.percentage = progress;
      }
    }
  }).then(response => {
    const res = response.data;

    if (res.code === 200) {
      onSuccess(res, file);
    } else {
      onError(res.msg || res.message, file);
    }

  }).catch(error => {
    console.log('上传error: ', error);
    onError(error, file);
  });
}

async function handleBeforeUpload(file) {

  // 文件大小判断
  if (option.maxSize) {
    // 文件最大大小
    const maxSize = 1 * 1024 * 1024 * option.maxSize;

    // 文件大小判断
    if (file.size > maxSize) {
      ElMessage({
        message: `文件大小不能超过${option.maxSize}M`,
        type: 'warning'
      });

      return false;
    }
  }

  // 文件类型判断
  if (option.uploadType) {
    // 去除空格
    const uploadTypes = option.uploadType.split(',').map(item => item.trim());

    const fileType = file.type;

    if (!uploadTypes.some(_uploadType => fileType.includes(_uploadType))) {
      ElMessage({
        message: `文件类型只能为${option.uploadType}`,
        type: 'warning'
      });

      return false;
    }
  }

  return true;
}

/**
 * 期望fileData格式
 * {
 *   name: '文件名',
 *   url: '文件地址',
 *   size: '文件大小',
 *   uid: '文件唯一标识',
 *   percentage: '文件上传百分比',
 * }
 */
function onSuccess(response, file) {

  const index = fileList.value.findIndex(item => item.uid === file.uid);

  const fileData = {
    name: response.data?.name || response.data?.fileName || file.name,
    url: response.data?.url || response.data?.fileUrl || response.data?.urlPath || response.data?.path || response.data,
    size: file.size,
    uid: file.uid,
    percentage: 100
  };

  fileList.value.splice(index, 1, fileData);
}

function onError(error, file) {
  const index = fileList.value.findIndex(item => item.uid === file.uid);

  ElMessage({
    message: `上传失败: ${error?.message}`,
    type: 'error'
  });

  fileList.value.splice(index, 1);
}

// 删除文件
function handleRemove(index) {
  fileList.value.splice(index, 1);
}

// 预览文件
function handlePreview(url) {
  window.open(getFullUrl(url));
}


const fileIcon = {
  file: '',
  word: '',
  excel: '',
  ppt: '',
  pdf: '',
  image: ''
};

const fileSuffixToFileIcon = {
  'pdf': 'pdf',
  'doc': 'word',
  'docx': 'word',
  'xls': 'excel',
  'xlsx': 'excel',
  'ppt': 'ppt',
  'pptx': 'ppt',
  'zip': 'zip',
  'rar': 'zip',
  '7z': 'zip',
  'txt': 'txt',
  'jpg': 'image',
  'jpeg': 'image',
  'png': 'image',
  'gif': 'image',
  'bmp': 'image',
  'mp3': 'audio',
  'wav': 'audio',
  'wma': 'audio',
  'mp4': 'video',
  'avi': 'video',
  'rmvb': 'video',
  'rm': 'video',
  'flv': 'video',
  'swf': 'video',
  'wmv': 'video'
};

// 获取文件类型
function getFileTypeByFileName(fileName) {
  const suffix = fileName.split('.').pop();

  return fileSuffixToFileIcon[suffix] || 'file';
}

// 获取文件图标
function getFileIconByFileName(fileName) {

  const type = getFileTypeByFileName(fileName);

  if (fileIcon[type]) {
    return fileIcon[type];
  }

  return fileIcon['file'];
}
</script>

<template>
  <div class="upload-file">
    <template v-if="uploadConfig.url">
      <div class="upload-file__template" v-if="templateFiles.length">
        <div>为了保证资料上传顺利，请先下载模板，并按照规范示例上传资料</div>

        <div v-for="item in templateFiles" :key="item.uid" class="upload-file__template__item">
          <a :href="item.url" download target="_blank">{{ item.name }}</a>
        </div>
      </div>

      <el-upload v-model:file-list="fileList" :limit="option.uploadLimit"
        :disabled="disabled || (fileList.length >= option.uploadLimit)" :show-file-list="false"
        :on-change="handleChange" :auto-upload="false">
        <div class="questionnaire__btn" :class="{
          'upload-file__btn--disabled': disabled || (fileList.length >= option.uploadLimit)
        }">
          {{ option.uploadText }}
          ({{ fileList.length }}/{{ option.uploadLimit }})
        </div>
      </el-upload>

      <div class="upload-file__item" v-for="(item, index) in fileList" :key="item.uid || item.url || item.name">
        <div class="upload-file__item__content">
          <img :src="getFileIconByFileName(item.name)" class="upload-file__item__icon" />
          <div class="upload-file__item__title">
            {{ item.name }}
          </div>
          <div class="upload-file__item__btn" @click="handlePreview(item.url)">预览</div>
          <div class="upload-file__item__btn" @click="handleRemove(index)">删除</div>
        </div>
        <el-progress :percentage="item.percentage" status="success" v-if="item.percentage"
          class="upload-file__item__percentage" />
      </div>
    </template>

    <div class="upload-file__no-api" v-else>
      未配置上传接口
    </div>
  </div>
</template>

<style scoped>
.upload-file {
  width: 100%;
}

.upload-file__item {
  border-radius: var(--br-2);
  margin: var(--m-1) 0;
  padding: var(--p-1);
  background-color: var(--bg-tertiary-color);
  color: var(--text-base-color);
  font-size: var(--fs-2);
  border: 1px solid var(--border-base-color);
  line-height: normal;
}

.upload-file__item__content {
  display: flex;
  align-items: center;
}

.upload-file__item__icon {
  display: block;
  width: 22px;
  height: 22px;
}

.upload-file__item__title {
  flex: 1;
  width: 0;
  word-wrap: break-word;
  word-break: normal;
  margin: 0 var(--m-1);
}

.upload-file__item__btn {
  cursor: pointer;
  font-size: var(--fs-1);
  padding: calc(var(--p-1) / 2) var(--p-2);
  background-color: transparent;
  transition: all 0.3s;
  border-radius: var(--br-1);
}

.upload-file__item__btn:hover {
  background-color: var(--primary-color);
  color: var(--primary-text-color);
}

.upload-file__item__percentage {
  margin-top: calc(var(--m-1) / 2);
}

.upload-file__item :deep(.el-progress__text) {
  display: none;
}

.upload-file__btn--disabled {
  background-color: #eff0f1;
  color: #303133;
  cursor: not-allowed;
}

.upload-file__template {
  background-color: var(--bg-tertiary-color);
  color: var(--text-base-color);
  font-size: var(--fs-2);
  padding: var(--p-1);
  border-radius: var(--br-2);
  margin-bottom: var(--m-1);
}

.upload-file__template__item {
  margin-top: var(--m-1);
}

.upload-file__no-api {
  background-color: var(--bg-tertiary-color);
  color: var(--text-base-color);
  font-size: var(--fs-2);
  padding: var(--p-1);
  border-radius: var(--br-2);
}
</style>